package com.weiquan.service.impl;

import com.weiquan.service.SmsService;
import com.weiquan.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * 短信服务实现类
 */
@Slf4j
@Service
public class SmsServiceImpl implements SmsService {

    @Autowired
    private RedisUtils redisUtils;

    @Value("${sms.enabled:false}")
    private boolean smsEnabled;

    @Value("${sms.provider:aliyun}")
    private String smsProvider;

    @Value("${sms.access-key:}")
    private String accessKey;

    @Value("${sms.access-secret:}")
    private String accessSecret;

    @Value("${sms.sign-name:维权力}")
    private String signName;

    // 验证码有效期（分钟）
    private static final int CODE_EXPIRE_MINUTES = 5;
    
    // 发送频率限制（秒）
    private static final int SEND_LIMIT_SECONDS = 60;
    
    // 每日发送限制
    private static final int DAILY_LIMIT = 10;

    // Redis键前缀
    private static final String CODE_PREFIX = "sms:code:";
    private static final String LIMIT_PREFIX = "sms:limit:";
    private static final String DAILY_PREFIX = "sms:daily:";

    // 短信模板
    private static final String REGISTER_TEMPLATE = "SMS_123456789"; // 注册验证码模板
    private static final String LOGIN_TEMPLATE = "SMS_123456790";    // 登录验证码模板
    private static final String RESET_TEMPLATE = "SMS_123456791";    // 重置密码模板

    @Override
    public boolean sendVerificationCode(String phoneNumber, String code) {
        if (!StringUtils.hasText(phoneNumber) || !StringUtils.hasText(code)) {
            log.error("手机号或验证码为空");
            return false;
        }

        // 检查发送频率限制
        if (!checkSendLimit(phoneNumber)) {
            log.warn("手机号{}发送频率过快", phoneNumber);
            return false;
        }

        try {
            if (smsEnabled) {
                // 调用真实短信服务
                boolean success = sendSmsWithProvider(phoneNumber, code, REGISTER_TEMPLATE);
                if (success) {
                    // 保存验证码到Redis
                    saveCodeToRedis(phoneNumber, code, "register");
                    // 更新发送限制
                    updateSendLimit(phoneNumber);
                    log.info("验证码发送成功，手机号：{}", phoneNumber);
                    return true;
                }
            } else {
                // 开发环境模拟发送
                log.info("模拟发送验证码到手机号：{}，验证码：{}", phoneNumber, code);
                saveCodeToRedis(phoneNumber, code, "register");
                updateSendLimit(phoneNumber);
                return true;
            }
        } catch (Exception e) {
            log.error("发送验证码失败，手机号：{}", phoneNumber, e);
        }

        return false;
    }

    @Override
    public boolean sendRegisterCode(String phoneNumber) {
        String code = generateCode();
        return sendVerificationCode(phoneNumber, code);
    }

    @Override
    public boolean sendLoginCode(String phoneNumber) {
        if (!checkSendLimit(phoneNumber)) {
            return false;
        }

        String code = generateCode();
        
        try {
            if (smsEnabled) {
                boolean success = sendSmsWithProvider(phoneNumber, code, LOGIN_TEMPLATE);
                if (success) {
                    saveCodeToRedis(phoneNumber, code, "login");
                    updateSendLimit(phoneNumber);
                    log.info("登录验证码发送成功，手机号：{}", phoneNumber);
                    return true;
                }
            } else {
                log.info("模拟发送登录验证码到手机号：{}，验证码：{}", phoneNumber, code);
                saveCodeToRedis(phoneNumber, code, "login");
                updateSendLimit(phoneNumber);
                return true;
            }
        } catch (Exception e) {
            log.error("发送登录验证码失败，手机号：{}", phoneNumber, e);
        }

        return false;
    }

    @Override
    public boolean sendResetPasswordCode(String phoneNumber) {
        if (!checkSendLimit(phoneNumber)) {
            return false;
        }

        String code = generateCode();
        
        try {
            if (smsEnabled) {
                boolean success = sendSmsWithProvider(phoneNumber, code, RESET_TEMPLATE);
                if (success) {
                    saveCodeToRedis(phoneNumber, code, "reset");
                    updateSendLimit(phoneNumber);
                    log.info("重置密码验证码发送成功，手机号：{}", phoneNumber);
                    return true;
                }
            } else {
                log.info("模拟发送重置密码验证码到手机号：{}，验证码：{}", phoneNumber, code);
                saveCodeToRedis(phoneNumber, code, "reset");
                updateSendLimit(phoneNumber);
                return true;
            }
        } catch (Exception e) {
            log.error("发送重置密码验证码失败，手机号：{}", phoneNumber, e);
        }

        return false;
    }

    @Override
    public boolean verifyCode(String phoneNumber, String code, String type) {
        if (!StringUtils.hasText(phoneNumber) || !StringUtils.hasText(code) || !StringUtils.hasText(type)) {
            return false;
        }

        String redisKey = CODE_PREFIX + type + ":" + phoneNumber;
        String savedCode = (String) redisUtils.get(redisKey);

        if (savedCode != null && savedCode.equals(code)) {
            // 验证成功后删除验证码
            redisUtils.delete(redisKey);
            log.info("验证码验证成功，手机号：{}，类型：{}", phoneNumber, type);
            return true;
        }

        log.warn("验证码验证失败，手机号：{}，类型：{}，输入码：{}", phoneNumber, type, code);
        return false;
    }

    @Override
    public String generateCode() {
        Random random = new Random();
        StringBuilder code = new StringBuilder();
        
        for (int i = 0; i < 6; i++) {
            code.append(random.nextInt(10));
        }
        
        return code.toString();
    }

    @Override
    public boolean checkSendLimit(String phoneNumber) {
        // 检查发送频率限制
        String limitKey = LIMIT_PREFIX + phoneNumber;
        if (redisUtils.hasKey(limitKey)) {
            log.warn("手机号{}发送过于频繁，请稍后再试", phoneNumber);
            return false;
        }

        // 检查每日发送限制
        String dailyKey = DAILY_PREFIX + phoneNumber;
        Integer dailyCount = (Integer) redisUtils.get(dailyKey);
        if (dailyCount != null && dailyCount >= DAILY_LIMIT) {
            log.warn("手机号{}今日发送次数已达上限", phoneNumber);
            return false;
        }

        return true;
    }

    @Override
    public boolean sendNotification(String phoneNumber, String message) {
        if (!StringUtils.hasText(phoneNumber) || !StringUtils.hasText(message)) {
            return false;
        }

        try {
            if (smsEnabled) {
                // 发送通知短信（这里需要根据实际短信服务商的API实现）
                log.info("发送通知短信到手机号：{}，内容：{}", phoneNumber, message);
                return true;
            } else {
                log.info("模拟发送通知短信到手机号：{}，内容：{}", phoneNumber, message);
                return true;
            }
        } catch (Exception e) {
            log.error("发送通知短信失败，手机号：{}", phoneNumber, e);
            return false;
        }
    }

    /**
     * 使用短信服务商发送短信
     */
    private boolean sendSmsWithProvider(String phoneNumber, String code, String templateCode) {
        switch (smsProvider.toLowerCase()) {
            case "aliyun":
                return sendWithAliyun(phoneNumber, code, templateCode);
            case "tencent":
                return sendWithTencent(phoneNumber, code, templateCode);
            case "huawei":
                return sendWithHuawei(phoneNumber, code, templateCode);
            default:
                log.error("不支持的短信服务商：{}", smsProvider);
                return false;
        }
    }

    /**
     * 阿里云短信发送
     */
    private boolean sendWithAliyun(String phoneNumber, String code, String templateCode) {
        try {
            // 这里集成阿里云短信SDK
            log.info("使用阿里云发送短信，手机号：{}，模板：{}", phoneNumber, templateCode);
            
            // 模拟发送成功
            return true;
            
        } catch (Exception e) {
            log.error("阿里云短信发送失败", e);
            return false;
        }
    }

    /**
     * 腾讯云短信发送
     */
    private boolean sendWithTencent(String phoneNumber, String code, String templateCode) {
        try {
            // 这里集成腾讯云短信SDK
            log.info("使用腾讯云发送短信，手机号：{}，模板：{}", phoneNumber, templateCode);
            
            // 模拟发送成功
            return true;
            
        } catch (Exception e) {
            log.error("腾讯云短信发送失败", e);
            return false;
        }
    }

    /**
     * 华为云短信发送
     */
    private boolean sendWithHuawei(String phoneNumber, String code, String templateCode) {
        try {
            // 这里集成华为云短信SDK
            log.info("使用华为云发送短信，手机号：{}，模板：{}", phoneNumber, templateCode);
            
            // 模拟发送成功
            return true;
            
        } catch (Exception e) {
            log.error("华为云短信发送失败", e);
            return false;
        }
    }

    /**
     * 保存验证码到Redis
     */
    private void saveCodeToRedis(String phoneNumber, String code, String type) {
        String redisKey = CODE_PREFIX + type + ":" + phoneNumber;
        redisUtils.set(redisKey, code, CODE_EXPIRE_MINUTES * 60);
    }

    /**
     * 更新发送限制
     */
    private void updateSendLimit(String phoneNumber) {
        // 设置发送频率限制
        String limitKey = LIMIT_PREFIX + phoneNumber;
        redisUtils.set(limitKey, "1", SEND_LIMIT_SECONDS);

        // 更新每日发送计数
        String dailyKey = DAILY_PREFIX + phoneNumber;
        Integer dailyCount = (Integer) redisUtils.get(dailyKey);
        if (dailyCount == null) {
            redisUtils.set(dailyKey, 1, 24 * 60 * 60); // 24小时过期
        } else {
            redisUtils.set(dailyKey, dailyCount + 1, 24 * 60 * 60);
        }
    }

    /**
     * 获取验证码剩余有效时间（秒）
     */
    public long getCodeExpireTime(String phoneNumber, String type) {
        String redisKey = CODE_PREFIX + type + ":" + phoneNumber;
        return redisUtils.getExpire(redisKey);
    }

    /**
     * 获取发送限制剩余时间（秒）
     */
    public long getSendLimitTime(String phoneNumber) {
        String limitKey = LIMIT_PREFIX + phoneNumber;
        return redisUtils.getExpire(limitKey);
    }

    /**
     * 获取今日剩余发送次数
     */
    public int getRemainingDailyCount(String phoneNumber) {
        String dailyKey = DAILY_PREFIX + phoneNumber;
        Integer dailyCount = (Integer) redisUtils.get(dailyKey);
        return DAILY_LIMIT - (dailyCount == null ? 0 : dailyCount);
    }

    /**
     * 清除验证码（管理员功能）
     */
    public boolean clearCode(String phoneNumber, String type) {
        String redisKey = CODE_PREFIX + type + ":" + phoneNumber;
        return redisUtils.delete(redisKey);
    }

    /**
     * 重置发送限制（管理员功能）
     */
    public boolean resetSendLimit(String phoneNumber) {
        String limitKey = LIMIT_PREFIX + phoneNumber;
        String dailyKey = DAILY_PREFIX + phoneNumber;
        
        boolean result1 = redisUtils.delete(limitKey);
        boolean result2 = redisUtils.delete(dailyKey);
        
        return result1 || result2;
    }
}